var fs = require('fs');

var _gulpUtil = require('gulp-util');

var _through = require('through2');

var _through2 = _interopRequireDefault(_through);

var _promise = require('promise');

var _promise2 = _interopRequireDefault(_promise);

var _deepExtend = require('deep-extend');

var _deepExtend2 = _interopRequireDefault(_deepExtend);

var _formatters = require('./formatters');

var formatters = _interopRequireWildcard(_formatters);

var _reporterFactory = require('./reporter-factory');

var _reporterFactory2 = _interopRequireDefault(_reporterFactory);

var htmlcs = require('htmlcs');

var htmlcsConfig = require('htmlcs/lib/config');

function _interopRequireWildcard(obj) {
    if (obj && obj.__esModule) {
        return obj;
    } else {
        var newObj = {};
        if (obj != null) {
            for (var key in obj) {
                if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
            }
        }
        newObj.default = obj;
        return newObj;
    }
}

function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}

var readFile = function(filePath) {
    return fs.readFileSync(filePath, {
        encoding: 'utf-8'
    });
};

var pluginName = 'gulp-htmlcs';

module.exports = function(options) {
    options = options || {};

    var pluginOptions = (0, _deepExtend2.default)({
        failAfterError: true,
        debug: false
    }, options);

    var lintOptions = (0, _deepExtend2.default)({}, options);

    var reporters = (pluginOptions.reporters || []).map(function(config) {
        return (0, _reporterFactory2.default)(config, pluginOptions);
    });

    var lintPromiseList = [];

    // Remove the stylelint options that cannot be used:
    delete lintOptions.files; // css code will be provided by gulp instead
    delete lintOptions.formatter; // formatters are defined in the `reporters` option

    // Remove gulp-stylelint options so that they don't interfere with stylelint options:
    delete lintOptions.reportOutputDir;
    delete lintOptions.reporters;
    delete lintOptions.debug;

    var hint = htmlcs.hint;

    function loadSpecifiedConfig(configFilePath) {
        try {
            return htmlcsConfig.parse(readFile(configFilePath));
        } catch (e) {
            console.log(e);
        }
    };

    if (pluginOptions.config) {
        var config = loadSpecifiedConfig(pluginOptions.config);
        hint = function(code) {
            return htmlcs.hint(code, config);
        };
    }

    function formatResult(result, source) {
        console.log(result);
        var errored = false;
        var warnings = result.map(function(item) {
            console.log(item);
            if (item.type == 'ERROR') errored = true;
            return {
                line: item.line,
                column: item.column,
                rule: item.rule,
                severity: item.type.toLowerCase(),
                text: item.message,
                code: item.code
            }
        });
        return {
            results: [{
                source: source,
                errored: errored,
                warnings: warnings,
                deprecations: [],
                invalidOptionWarnings: [],
                ignored: false
            }]
        };
    }

    function onFile(file, encoding, done) {
        if (file.isNull()) {
            done(null, file);
            return;
        }

        if (file.isStream()) {
            this.emit('error', new _gulpUtil.PluginError(pluginName, 'Streaming is not supported'));
            done();
            return;
        }

        lintPromiseList.push(formatResult(hint(file.contents.toString()), file.path));

        done(null, file);
    }

    function passLintResultsThroughReporters(lintResults) {
        var warnings = lintResults.reduce(function(accumulated, res) {
            return accumulated.concat(res.results);
        }, []);
        return _promise2.default.all(reporters.map(function(reporter) {
            return reporter(warnings);
        })).then(function() {
            return lintResults;
        });
    }

    function isErrorSeverity(warning) {
        return warning.severity === 'error';
    }

    function onStreamEnd(done) {
        var _this = this;

        _promise2.default.all(lintPromiseList).then(passLintResultsThroughReporters).then(function(lintResults) {
            process.nextTick(function() {
                var errorCount = lintResults.reduce(function(sum, res) {
                    var errors = res.results[0].warnings.filter(isErrorSeverity);
                    return sum + errors.length;
                }, 0);
                if (pluginOptions.failAfterError && errorCount > 0) {
                    var errorMessage = 'Failed with ' + errorCount + ' ' + (errorCount === 1 ? 'error' : 'errors');
                    _this.emit('error', new _gulpUtil.PluginError(pluginName, errorMessage));
                }
                done();
            });
        }).catch(function(error) {
            process.nextTick(function() {
                _this.emit('error', new _gulpUtil.PluginError(pluginName, error, {
                    showStack: Boolean(pluginOptions.debug)
                }));
                done();
            });
        });
    }

    return _through2.default.obj(onFile, onStreamEnd);
};